package com.Humanities.orders.service.impl;

import com.Humanities.orders.service.OrderService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xuecheng.base.exception.XueChengPlusException;
import com.xuecheng.base.utils.QRCodeUtil;
import com.xuecheng.messagesdk.model.po.MqMessage;
import com.xuecheng.messagesdk.service.MqMessageService;
import com.Humanities.orders.config.AlipayConfig;
import com.Humanities.orders.config.PayNotifyConfig;
import com.Humanities.orders.mapper.XcOrdersGoodsMapper;
import com.Humanities.orders.mapper.XcOrdersMapper;
import com.Humanities.orders.mapper.XcPayRecordMapper;
import com.xuecheng.orders.model.dto.AddOrderDto;
import com.xuecheng.orders.model.dto.PayRecordDto;
import com.xuecheng.orders.model.dto.PayStatusDto;
import com.xuecheng.orders.model.po.XcOrders;
import com.xuecheng.orders.model.po.XcOrdersGoods;
import com.xuecheng.orders.model.po.XcPayRecord;
import com.Humanities.orders.util.IdWorkerUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
    @Autowired
    XcOrdersMapper ordersMapper;
    @Autowired
    XcOrdersGoodsMapper ordersGoodsMapper;

    @Autowired
    XcPayRecordMapper payRecordMapper;

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Autowired
    MqMessageService mqMessageService;



    @Autowired
    OrderService currentProxy;
    @Value("${pay.qrcodeurl}")
    String qrcodeurl;

    @Value("${pay.alipay.APP_ID}")
    String APP_ID;
    @Value("${pay.alipay.APP_PRIVATE_KEY}")
    String APP_PRIVATE_KEY;

    @Value("${pay.alipay.ALIPAY_PUBLIC_KEY}")
    String ALIPAY_PUBLIC_KEY;

    @Transactional
    @Override
    public PayRecordDto createOrder(String userId, AddOrderDto addOrderDto) {

        //添加商品订单
        XcOrders orders = saveXcOrders(userId, addOrderDto);

        if(orders==null){
            XueChengPlusException.cast("订单创建失败");
        }
        //生成支付记录
        XcPayRecord payRecord = createPayRecord(orders);
        //生成二维码
        String qrCode = null;
        try {
            //url要可以被模拟器访问到，url为下单接口(稍后定义)
            String url = String.format(qrcodeurl, payRecord.getPayNo());
            //这行代码的含义是使用 String.format 方法将 qrcodeurl 中的占位符替换为 payRecord.getPayNo() 的值，生成一个完整的 URL 字符串。
            qrCode = new QRCodeUtil().createQRCode(url, 200, 200);
        } catch (IOException e) {
            XueChengPlusException.cast("生成二维码出错");
        }
        PayRecordDto payRecordDto = new PayRecordDto();
        BeanUtils.copyProperties(payRecord,payRecordDto);
        payRecordDto.setQrcode(qrCode);

        return payRecordDto;
    }
    /**
     * @param userId      用户id
     * @param addOrderDto 订单信息
     * @return XcOrders 订单信息
     * @description 保存订单
     * @author Mr.M
     * @date 2022/10/4 11:02
     */
    public XcOrders saveXcOrders(String userId, AddOrderDto addOrderDto){
        //判断幂是否存在
        XcOrders order = getOrderByBusinessId(addOrderDto.getOutBusinessId());
        if (order != null) {
            log.error("订单已存在，businessId:{}", addOrderDto.getOutBusinessId());
            return order;
        }
        //创建订单对象
        XcOrders xcOrders = new XcOrders();
        Long id = IdWorkerUtils.getInstance().nextId();
        xcOrders.setId(id);
        xcOrders.setUserId(userId);
        xcOrders.setOrderName(addOrderDto.getOrderName());
        xcOrders.setOrderDescrip(addOrderDto.getOrderDescrip());
        xcOrders.setTotalPrice(addOrderDto.getTotalPrice());
        xcOrders.setOutBusinessId(addOrderDto.getOutBusinessId());
        xcOrders.setStatus("600001");//未支付
        xcOrders.setOrderType(addOrderDto.getOrderType());
        xcOrders.setOrderDetail(addOrderDto.getOrderDetail());
        //保存订单
        ordersMapper.insert(xcOrders);

        //创建订单明细对象
        String orderDetailJson = addOrderDto.getOrderDetail();
        //解析json
          //将json转换为对象
        List<XcOrdersGoods> xcOrdersGoodsList = JSON.parseArray(orderDetailJson, XcOrdersGoods.class);
        xcOrdersGoodsList.forEach(goods -> {
            XcOrdersGoods xcOrdersGoods = new XcOrdersGoods();
            BeanUtils.copyProperties(goods,xcOrdersGoods);
            xcOrdersGoods.setOrderId(id);//订单号
            ordersGoodsMapper.insert(xcOrdersGoods);
        });
        return xcOrders;
    }

    //根据业务id查询订单
    public XcOrders getOrderByBusinessId(String businessId){
        XcOrders xcOrders = ordersMapper.selectOne(
                new LambdaQueryWrapper<XcOrders>().eq(XcOrders::getOutBusinessId, businessId)
        );
        if (xcOrders == null) {
            log.error("订单不存在，businessId:{}", businessId);
            return null;
        }
        return xcOrders;
    }
    //创建支付记录
    public XcPayRecord createPayRecord(XcOrders orders){
        if(orders==null){
            XueChengPlusException.cast("订单不存在");
        }
        if(orders.getStatus().equals("600002")){
            XueChengPlusException.cast("订单已支付");
        }
        XcPayRecord payRecord = new XcPayRecord();
        //生成支付交易流水号
        long payNo = IdWorkerUtils.getInstance().nextId();
        payRecord.setPayNo(payNo);
        payRecord.setOrderId(orders.getId());//商品订单号
        payRecord.setOrderName(orders.getOrderName());
        payRecord.setTotalPrice(orders.getTotalPrice());
        payRecord.setCurrency("CNY");
     //   payRecord.setCreateDate(LocalDateTime.now()); 自动填充
        payRecord.setStatus("601001");//未支付
        payRecord.setUserId(orders.getUserId());
        payRecordMapper.insert(payRecord);
        return payRecord;
    }

    @Override
    public XcPayRecord getPayRecordByPayno(String payNo) {
        XcPayRecord xcPayRecord = payRecordMapper.selectOne(new LambdaQueryWrapper<XcPayRecord>().eq(XcPayRecord::getPayNo, payNo));
        return xcPayRecord;
    }



   //查询支付结果
    @Override
    public PayRecordDto queryPayResult(String payNo) {
        //查询支付记录表
        XcPayRecord xcPayRecord = payRecordMapper.selectOne(new LambdaQueryWrapper<XcPayRecord>().eq(XcPayRecord::getPayNo, payNo));
        if (xcPayRecord == null) {
            XueChengPlusException.cast("支付记录不存在，请刷新二维码");
        }
        PayRecordDto payRecordDto = new PayRecordDto();
        if (xcPayRecord.getStatus().equals("601002")) {
            log.debug("订单已支付，订单号:{}", payNo);
            BeanUtils.copyProperties(xcPayRecord, payRecordDto);
            return payRecordDto;
        }
        //从支付宝查询支付结果
        PayStatusDto payStatusDto = queryPayResultFromAlipay(payNo);
        //保存支付状态，修改支付记录表和订单表
        //保存支付结果
        currentProxy.saveAliPayStatus( payStatusDto);

        //查询支付记录表
        xcPayRecord = payRecordMapper.selectOne(new LambdaQueryWrapper<XcPayRecord>().eq(XcPayRecord::getPayNo, payNo));
        BeanUtils.copyProperties(xcPayRecord, payRecordDto);
        return payRecordDto;


    }

    @Transactional
    //更新保存支付状态（涉及orders、pay_record表）
    public void saveAliPayStatus(PayStatusDto payStatusDto){
        //支付流水号
        String payNo = payStatusDto.getOut_trade_no();
        //支付结果
        String trade_status = payStatusDto.getTrade_status();


        //查询支付记录
        XcPayRecord payRecord = payRecordMapper.selectOne(new LambdaQueryWrapper<XcPayRecord>().eq(XcPayRecord::getPayNo, payNo));
        if (payRecord == null) {
            XueChengPlusException.cast("支付记录不存在，请刷新二维码");
        }
        log.debug("收到支付结果:{},支付记录:{}}", trade_status,payRecord.toString());
       if(payStatusDto.getTrade_status().equals("TRADE_SUCCESS")){
           //支付金额变为分
           Float totalPrice = payRecord.getTotalPrice() * 100;
           Float total_amount = Float.parseFloat(payStatusDto.getTotal_amount()) * 100;
           //校验是否一致
           if (totalPrice.intValue() != total_amount.intValue()) {
               //校验失败
               log.info("校验支付结果失败,支付记录:{},APP_ID:{},totalPrice:{}" ,payRecord.toString(),payStatusDto.getApp_id(),total_amount.intValue());
               XueChengPlusException.cast("校验支付结果失败");
           }
           log.debug("更新支付结果,支付交易流水号:{},支付结果:{}", payNo, trade_status);
           XcPayRecord payRecord_u = new XcPayRecord();
           payRecord_u.setStatus("601002");//支付成功
           payRecord_u.setOutPayChannel("Alipay");
           payRecord_u.setOutPayNo(payStatusDto.getTrade_no());//支付宝交易号
           payRecord_u.setPaySuccessTime(LocalDateTime.now());//通知时间
           int update1 = payRecordMapper.update(payRecord_u, new LambdaQueryWrapper<XcPayRecord>().eq(XcPayRecord::getPayNo, payNo));
           if (update1 > 0) {
               log.info("更新支付记录状态成功:{}", payRecord_u.toString());
           } else {
               log.info("更新支付记录状态失败:{}", payRecord_u.toString());
               XueChengPlusException.cast("更新支付记录状态失败");
           }
           //更新订单状态
           //关联的订单号
           Long orderId = payRecord.getOrderId();
           XcOrders orders = ordersMapper.selectById(orderId);
           if (orders == null) {
               log.info("根据支付记录[{}}]找不到订单", payRecord_u.toString());
               XueChengPlusException.cast("根据支付记录找不到订单");
           }
           XcOrders order_u = new XcOrders();
           order_u.setStatus("600002");//支付成功
           int update = ordersMapper.update(order_u, new LambdaQueryWrapper<XcOrders>().eq(XcOrders::getId, orderId));
           if (update > 0) {
               log.info("更新订单表状态成功,订单号:{}", orderId);
           } else {
               log.info("更新订单表状态失败,订单号:{}", orderId);
               XueChengPlusException.cast("更新订单表状态失败");
           }
              //发送支付结果通知
           //保存消息记录,参数1：支付结果通知类型，2: 业务id，3:业务类型
           MqMessage mqMessage = mqMessageService.addMessage(PayNotifyConfig.MESSAGE_TYPE, orders.getOutBusinessId(), orders.getOrderType(), null);
           //通知消息
           notifyPayResult(mqMessage);
       }

    }


    /**
     * 请求支付宝查询支付结果
     * @param payNo 支付交易号
     * @return 支付结果
     */
    public PayStatusDto queryPayResultFromAlipay(String payNo) {

        //========请求支付宝查询支付结果=============
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.URL, APP_ID, APP_PRIVATE_KEY, "json", AlipayConfig.CHARSET, ALIPAY_PUBLIC_KEY, AlipayConfig.SIGNTYPE); //获得初始化的AlipayClient
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        JSONObject bizContent = new JSONObject();
        bizContent.put("out_trade_no", payNo);
        request.setBizContent(bizContent.toString());
        AlipayTradeQueryResponse response = null;
        try {
            response = alipayClient.execute(request);
            if (!response.isSuccess()) {
                XueChengPlusException.cast("请求支付查询查询失败");
            }
        } catch (AlipayApiException e) {
            log.error("请求支付宝查询支付结果异常:{}", e.toString(), e);
            XueChengPlusException.cast("请求支付查询查询失败");
        }

        //获取支付结果
        String resultJson = response.getBody();
        //转map
        Map resultMap = JSON.parseObject(resultJson, Map.class);
        Map alipay_trade_query_response = (Map) resultMap.get("alipay_trade_query_response");
        //支付结果
        String trade_status = (String) alipay_trade_query_response.get("trade_status");
        String total_amount = (String) alipay_trade_query_response.get("total_amount");
        String trade_no = (String) alipay_trade_query_response.get("trade_no");
        //保存支付结果
        PayStatusDto payStatusDto = new PayStatusDto();
        payStatusDto.setOut_trade_no(payNo);
        payStatusDto.setTrade_status(trade_status);
        payStatusDto.setApp_id(APP_ID);
        payStatusDto.setTrade_no(trade_no);
        payStatusDto.setTotal_amount(total_amount);
        return payStatusDto;

    }
   @Override
    public void notifyPayResult(MqMessage message) {

        // 将消息对象转换为 JSON 字符串
        String msg = JSON.toJSONString(message);
        // 设置消息为持久化模式
        Message msgObj = MessageBuilder.withBody(msg.getBytes(StandardCharsets.UTF_8))
                .setDeliveryMode(MessageDeliveryMode.PERSISTENT)
                .build();
        // 创建全局唯一的消息 ID，并封装到 CorrelationData 中
        CorrelationData correlationData = new CorrelationData(message.getId().toString());
        // 添加回调函数，用于处理消息发送的结果
        correlationData.getFuture().addCallback(
                result -> {
                    if(result.isAck()){
                        // 如果消息发送成功，记录日志
                        log.debug("通知支付结果消息发送成功, ID:{}", correlationData.getId());
                        // 删除消息表中的记录,且插入到历史消息表
                        mqMessageService.completed(message.getId());
                    }else{
                        // 如果消息发送失败，记录失败原因
                        log.error("通知支付结果消息发送失败, ID:{}, 原因{}",correlationData.getId(), result.getReason());
                    }
                },
                ex -> log.error("消息发送异常, ID:{}, 原因{}",correlationData.getId(),ex.getMessage()) // 处理发送异常
        );
        // 发送消息到指定的交换机
        rabbitTemplate.convertAndSend(PayNotifyConfig.PAYNOTIFY_EXCHANGE_FANOUT, "", msgObj,correlationData);

    }


}